<?php

namespace App\Services;


use Elastic\Elasticsearch\Client;
use Elastic\Elasticsearch\ClientBuilder;

abstract class BaseService
{
    /**
     * @var Client
     */
    protected $client;

    /**
     * 索引名称
     * @var string
     */
    protected $index = '';

    /**
     * 索引类型
     * @var string
     */
    protected $type = '';

    /**
     * 检索must条件
     * @var array
     */
    protected $must = [];

    /**
     * 检索should 条件
     * @var array
     */
    protected $should = [];

    /**
     * 聚合查询
     * @var array
     */
    protected $aggs = [];

    /**
     * 页码
     * @var int
     */
    protected $from = 0;

    /**
     * 每页条数
     * @var int
     */
    protected $size = 10;

    /**
     * 排序
     * @var array
     */
    protected $sort = [];

    /**
     * 检索字段，为空时检索所有字段
     * @var array
     */
    protected $source = [];

    /**
     * 高亮字段
     * @var array
     */
    protected $highLight = [];

    /**
     * 组合查询数组
     * @var array
     */
    protected $params = [];

    protected $refresh = true;

    public function __construct()
    {
        $this->client = ClientBuilder::create();
        $hosts = env("ELASTICSEARCH_HOST");
        $username = env("ELASTICSEARCH_USERNAME");
        $password = env("ELASTICSEARCH_PASSWORD");
        $this->client->setHosts([$hosts])
            ->setSSLVerification(false);
        if (!empty($username) && !empty($password)) {
            $this->client->setBasicAuthentication($username, $password);
        }
        $this->client = $this->client->build();
    }

    /**
     * @return string
     */
    public function getIndex(): string
    {
        return $this->index;
    }

    /**
     * @param string $index
     */
    public function setIndex(string $index): void
    {
        $this->index = $index;
    }

    /**
     * @return string
     */
    public function getType(): string
    {
        return $this->type;
    }

    /**
     * @param string $type
     */
    public function setType(string $type): void
    {
        $this->type = $type;
    }

    /**
     * @return array
     */
    public function getMust(): array
    {
        return $this->must;
    }

    /**
     * @param array $must
     */
    public function setMust(array $must): void
    {
        $this->must = $must;
    }

    /**
     * @return array
     */
    public function getShould(): array
    {
        return $this->should;
    }

    /**
     * @param array $should
     */
    public function setShould(array $should): void
    {
        $this->should = $should;
    }

    /**
     * @return array
     */
    public function getAggs(): array
    {
        return $this->aggs;
    }

    /**
     * @param array $aggs
     */
    public function setAggs(array $aggs): void
    {
        $this->aggs = $aggs;
    }

    /**
     * @return int
     */
    public function getFrom(): int
    {
        return $this->from;
    }

    /**
     * @param int $from
     */
    public function setFrom(int $from): void
    {
        $this->from = $from;
    }

    /**
     * @return int
     */
    public function getSize(): int
    {
        return $this->size;
    }

    /**
     * @param int $size
     */
    public function setSize(int $size): void
    {
        $this->size = $size;
    }

    /**
     * @return array
     */
    public function getSort(): array
    {
        return $this->sort;
    }

    /**
     * @param array $sort
     */
    public function setSort(array $sort): void
    {
        $this->sort = $sort;
    }

    /**
     * @return array
     */
    public function getSource(): array
    {
        return $this->source;
    }

    /**
     * @param array $source
     */
    public function setSource(array $source): void
    {
        $this->source = $source;
    }

    /**
     * @return array
     */
    public function getHighLight(): array
    {
        return $this->highLight;
    }

    /**
     * @param array $highLight
     */
    public function setHighLight(array $highLight): void
    {
        $this->highLight = $highLight;
    }

    public function getParams() :array
    {
        $this->params = [];
        if (!empty($this->getIndex())) {
            $this->params["index"] = $this->getIndex();
        }

        if (!empty($this->getType())) {
            $this->params["type"] = $this->getType();
        }

        if (!empty($this->getSource())) {
            $this->params["_source"] = $this->getSource();
        }

        if (!empty($this->getSort())) {
            $this->params["body"]["sort"][] = $this->getSort();
        }

        if (!empty($this->getMust())) {
            $this->params["body"]["query"]["bool"]["must"] = $this->getMust();
        }

        if (!empty($this->getShould())) {
            $this->params["body"]["query"]["bool"]["should"] = $this->getShould();
        }

        if (!empty($this->getAggs())) {
            $this->params["body"]["aggs"] = $this->getAggs();
        }

        //高亮
        if (!empty($this->getHighLight())) {
            $highLight = [];
            foreach ($this->getHighLight() as $field) {
                $highLight["fields"][$field] = [
                    'pre_tags' => '<strong>',
                    'post_tags' => '</strong>',
                    'number_of_fragments' => 0
                ];
            }
            $this->params["body"]["highlight"] = $highLight;
        }

        // 分页
        $this->params["from"] = $this->getFrom();
        $this->params["size"] = $this->getSize();

        return $this->params;
    }

    public function setParams(array $params) :void
    {
        $this->params = $params;
    }

    public function reset()
    {
        $this->must = [];
        $this->should = [];
        $this->aggs = [];
        $this->from = 0;
        $this->size = 10;
        $this->sort = [];
        $this->source = [];
        $this->highLight = [];
    }

    public function search() :array
    {
        $params = $this->getParams();
        $results = $this->client->search($params);
        return $this->out($results);
    }

    public function out($results) :array
    {
        $total = $results["hits"]["total"];
        $data = [];
        if ($total > 0) {
            foreach ($results["hits"]["hits"] as $row) {
                $data[] = $row["_source"];
            }
        }
        $aggs = [];
        if (isset($results["aggregations"])) {
            foreach ($results["aggregations"] as $key => $row) {
                $aggs[$key] = $row["buckets"];
            }
        }

        $result = [
            'total' => $total,
            'data' => $data
        ];

        if (!empty($aggs)) {
            $result["aggs"] = $aggs;
        }
        return $result;
    }

    public function create($id, $data, $refresh = false)
    {
        $params = [];
        if (!empty($this->getIndex())) {
            $params["index"] = $this->getIndex();
        }

        if (!empty($this->getType())) {
            $params["type"] = $this->getType();
        }

        if ($refresh === true) {
            $params["refresh"] = true;
        }

        $params['id'] = $id;
        $params['body'] = $data;
        $result = $this->client->create($params);
        return $result["result"];
    }


    public function update($id, $data, $refresh = false)
    {
        $params = [];
        if (!empty($this->getIndex())) {
            $params["index"] = $this->getIndex();
        }

        if (!empty($this->getType())) {
            $params["type"] = $this->getType();
        }

        if ($refresh === true) {
            $params["refresh"] = true;
        }

        $params['id'] = $id;
        $params['body']['doc'] = $data;
        $result = $this->client->update($params);
        return $result["result"];
    }

    public function delete($id, $refresh = false)
    {
        $params = [];
        if (!empty($this->getIndex())) {
            $params["index"] = $this->getIndex();
        }

        if (!empty($this->getType())) {
            $params["type"] = $this->getType();
        }

        if ($refresh === true) {
            $params["refresh"] = true;
        }

        $params['id'] = $id;
        $result = $this->client->delete($params);
        return $result;
    }


    /**
     * 创建索引
     * @param array $mappings
     * @return array|bool
     */
    public function createIndex(array $mappings)
    {
        $index = $this->getIndex();
        $params = [];
        if (!empty($index)) {
            $params["index"] = $index;
            $params['body'] = [
                'mappings' => [
                    'properties' => $mappings
                ]
            ];
        }

        $existParams["index"] = $index;
        if (!$this->client->indices()->exists($existParams)) {
            return $this->client->indices()->create($params);
        }
        return false;
    }
}
